﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace AllenalaMente.Games.Lost
{
    enum GamePhaseAnimation
    {
        Presenta,
        Nascondi,
        Rimuovi,
        Mostra,
        Chiedi,
        Attendi,
        Risultato
    }

    public partial class Lost : UserControl, GameInterface
    {
        private Random rnd = new Random();

        // UI
        private UITimer UIgameTimer;
        private UIScore UIgameScore;

        private DispatcherTimer timer = new DispatcherTimer(), startTimer;
        private TimeSpan startTime;
        private float gameTime;
        private GamePhaseAnimation phase = GamePhaseAnimation.Presenta;
        public event GameEvent GameEnd;

        private List<Item> items = new List<Item>();
        private List<Item> itemSolution = new List<Item>();

        private int giuste = 0, sbagliate = 0, points = 0, difficulty = 1;
        private int elemNum = 3; // Numero di Elementi mostrati 
        private int selectionNum = 3; // Numero di opzioni di risposta visualizzate
        private int ItemRemoved; // Indice dell'Elemento nascosto

        private Point[] positions = new Point[6];

        private Item cilindroFront, cilindroBack; // Cilindro

        public Lost()
        {
            InitializeComponent();

            // Posizioni di default degli Items
            positions[0] = new Point(130, 70);
            positions[1] = new Point(190, 240);
            positions[2] = new Point(625, 35);
            positions[3] = new Point(550, 230);
            positions[4] = new Point(45, 180);
            positions[5] = new Point(690, 145);

            //ResetGame();

            // Start timer
            startTimer = new DispatcherTimer();
            startTimer.Interval = TimeSpan.FromMilliseconds(600);
            startTimer.Tick += new EventHandler(startTimer_Tick);
            startTimer.Start();
            startTime = TimeSpan.FromSeconds(3);
            TextBlockReady.Text = Locale.Strings.Ready;

            // Timer
            timer.Interval = TimeSpan.FromMilliseconds(10);
            timer.Tick += Update;
            //timer.Start();

            // UI Game timer
            UIgameTimer = new UITimer(60);
            LayoutRoot.Children.Add(UIgameTimer);
            UIgameTimer.timeOut += new EventHandler(game_TimeOut);
            //UIgameTimer.Start();

            // UI Game Score
            UIgameScore = new UIScore();
            LayoutRoot.Children.Add(UIgameScore);
            Canvas.SetLeft(UIgameScore, 750);
        }

        public void Clear()
        {
            canvasGame.Children.Clear();
            canvasSolution.Children.Clear();

            timer.Stop();
            timer.Tick -= Update;

            UIgameTimer.Stop();

            items.Clear();
            itemSolution.Clear();
        }

        private void ResetGame()
        {
            items.Clear();
            itemSolution.Clear();
            canvasSolution.Children.Clear();

            gameTime = 0;
            HideBalloon();
            ShowBalloon(Locale.Strings.LostWarning, "");

            canvasGame.Children.Clear();

            // Estrae Elementi
            for (int i = 0; i < elemNum; i++)
            {
                Point p = positions[i];

                int r = rnd.Next(8);

                string path = "/AllenalaMente;component/Assets/Images/Lost/Item0" + r + ".png";

                Item item = new Item(path, p);
                item.setDimension(60, 60);
                Canvas.SetZIndex(item, 2);
                item.Opacity = 0;

                items.Add(item);
                canvasGame.Children.Add(item);
            }

            // Cilindro
            cilindroBack = new Item("/AllenalaMente;component/Assets/Images/Lost/Cilindro.png", new Point(320, 130));
            cilindroBack.setDimension(150, 200);
            cilindroBack.imageItem.Stretch = Stretch.Uniform;
            Canvas.SetZIndex(cilindroBack, 1);
            canvasGame.Children.Add(cilindroBack);

            cilindroFront = new Item("/AllenalaMente;component/Assets/Images/Lost/CilindroFront.png", new Point(320, 130));
            cilindroFront.setDimension(150, 200);
            cilindroFront.imageItem.Stretch = Stretch.Uniform;
            Canvas.SetZIndex(cilindroFront, 3);
            canvasGame.Children.Add(cilindroFront);

            phase = GamePhaseAnimation.Presenta;
        }

        private void Update(object sender, EventArgs e)
        {
            //gameTime += 0.020f;
            gameTime += 0.01f;

            switch (phase)
            {
                case GamePhaseAnimation.Presenta:

                    //if (gameTime > 1.0f)
                    //{
                    for (int i = 0; i < items.Count; i++)
                    {
                        items[i].FadeIn();
                    }

                    // Attiva Evento Click per cominciare il gioco
                    cilindroFront.MouseLeftButtonDown += Box_MouseLeftButtonDown;
                    canvasBalloon.MouseLeftButtonDown += Box_MouseLeftButtonDown;

                    phase = GamePhaseAnimation.Nascondi;
                    gameTime = -0.5f;

                    // Visualizza messaggio e conto alla rovescia
                    textBlockMessage.Text = Locale.Strings.LostWarning + " \n" + 5;
                    textBlockMessage2.Text = Locale.Strings.LostWarningStart;
                    //}

                    break;

                case GamePhaseAnimation.Nascondi:
                    // Visualizza messaggio e conto alla rovescia
                    textBlockMessage.Text = Locale.Strings.LostWarning + " \n" + (5 - Math.Ceiling(gameTime));
                    textBlockMessage2.Text = Locale.Strings.LostWarningStart;

                    if (gameTime > 4.0f)
                    {
                        // Rimuove eventi associati ad elementi
                        cilindroFront.MouseLeftButtonDown -= Box_MouseLeftButtonDown;
                        canvasBalloon.MouseLeftButtonDown -= Box_MouseLeftButtonDown;

                        // Nasconde gli elementi - Entrata nel cilindro
                        HideItems();

                        gameTime = 0;
                        phase = GamePhaseAnimation.Rimuovi;

                        // Nasconde balloon informativo
                        HideBalloon();
                    }

                    break;

                case GamePhaseAnimation.Rimuovi:
                    if (gameTime > 0.5f)
                    {
                        phase = GamePhaseAnimation.Mostra;
                        gameTime = 0;
                    }

                    break;

                case GamePhaseAnimation.Mostra:
                    if (gameTime > 0.2f)
                    {
                        // Nasconde un elemento - Opacity 0
                        HideItem();

                        // Mostra gli elementi - Uscita da cilindro
                        ShowItems();

                        phase = GamePhaseAnimation.Chiedi;
                        gameTime = 0;
                    }
                    break;

                case GamePhaseAnimation.Chiedi:
                    if (gameTime > 0.2f)
                    {
                        // Mostra opzioni di risposta
                        SetAndShowOptions();

                        gameTime = 0;
                        phase = GamePhaseAnimation.Attendi;
                    }
                    break;

                case GamePhaseAnimation.Attendi:

                    if (gameTime > 0.5f && gameTime < 0.53f)
                    {
                        // Visualizza messaggio e attende
                        ShowBalloon(Locale.Strings.LostWarningMissing, "");
                    }

                    break;

                case GamePhaseAnimation.Risultato:
                    textBlockMessage.Text = "";
                    textBlockMessage2.Text = "";

                    if (gameTime > 0.5f)
                    {
                        ResetGame();
                    }
                    break;
            }
        }

        private void HideItem()
        {
            // Estrai un elemento
            ItemRemoved = rnd.Next(elemNum);
            // Nasconde elemento
            items[ItemRemoved].Opacity = 0;
        }

        private void SetAndShowOptions()
        {
            int ItemDim = 80; // Dimensione item di risposta
            int offset = 280; // Distanza tra le risposte

            if (selectionNum == 4) offset = 240;
            if (selectionNum == 5) offset = 200;
            if (selectionNum == 6) offset = 160;

            List<int> indexList = new List<int>();

            for (int i = 0; i < 8; i++)
            {
                indexList.Add(i);
            }

            // Estrazione opzioni di risposta

            bool hasSolution = false;

            // Creo n risposte random, anche con ripetizioni
            for (int i = 0; i < selectionNum; i++)
            {
                int r = rnd.Next(indexList.Count);

                int n = indexList[r];

                string path = "/AllenalaMente;component/Assets/Images/Lost/Item0" + n + ".png";
                indexList.Remove(n);

                if (!hasSolution && items[ItemRemoved].path == path) hasSolution = true;

                Item item = new Item(path, new Point((ItemDim * i) + offset - 10, 0));

                itemSolution.Add(item);
            }

            // Se tra le risposte create non c'è quella corretta, la inserisco al posto di una create
            if (!hasSolution)
            {
                int rn = rnd.Next(selectionNum);

                Item it = new Item(items[ItemRemoved].path, itemSolution[rn].position);
                it.setDimension(ItemDim, ItemDim);
                it.Opacity = 0;
                itemSolution[rn] = it;
            }

            canvasSolution.Children.Clear();

            for (int i = 0; i < selectionNum; i++)
            {
                // Inserisco i bottoni delle risposte
                itemSolution[i].setDimension(ItemDim, ItemDim);
                itemSolution[i].Opacity = 1;
                itemSolution[i].rectangle.Opacity = 1;

                canvasSolution.Children.Add(itemSolution[i]);

                // Visualizzo i bottoni
                itemSolution[i].FadeIn();

                // Associo evento 
                itemSolution[i].MouseLeftButtonDown += solution_MouseLeftButtonDown;
            }
        }

        # region Animations

        private void HideItems()
        {
            // Nascondi
            for (int i = 0; i < elemNum; i++)
            {
                items[i].Hide();
            }
        }

        private void ShowItems()
        {
            // Mostra
            for (int i = 0; i < elemNum; i++)
            {
                items[i].Show();
            }
        }

        public void ShowBalloon(string text1, string text2)
        {
            if (text1 == Locale.Strings.LostWarningCorrect)
            {
                imgGiusto.Opacity = 1;
                FadeOut(canvasBalloon);
                FadeOut(imgGiusto);
                return;
            }

            if (text1 == Locale.Strings.LostWarningWrong)
            {
                imgSbagliato.Opacity = 1;
                FadeOut(canvasBalloon);
                FadeOut(imgSbagliato);
                return;
            }

            textBlockMessage.Text = text1;
            textBlockMessage2.Text = text2;

            FadeIn(canvasBalloon);
            FadeIn(textBlockMessage);
            FadeIn(textBlockMessage2);
        }

        public void HideBalloon()
        {
            FadeOut(canvasBalloon);
            FadeOut(textBlockMessage);
            FadeOut(textBlockMessage2);
        }

        // FADE IN
        public void FadeIn(UIElement elem)
        {
            DoubleAnimation doubleAnimation = new DoubleAnimation();
            doubleAnimation.From = 0;
            doubleAnimation.To = 1;
            doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(0.5));

            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Opacity"));
            Storyboard.SetTarget(doubleAnimation, elem);

            Storyboard sb = new Storyboard();
            sb.Children.Add(doubleAnimation);
            sb.Begin();
        }

        // FADE OUT
        public void FadeOut(UIElement elem)
        {
            DoubleAnimation doubleAnimation = new DoubleAnimation();
            doubleAnimation.From = 1;
            doubleAnimation.To = 0;
            doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));

            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Opacity"));
            Storyboard.SetTarget(doubleAnimation, elem);

            Storyboard sb = new Storyboard();
            sb.Children.Add(doubleAnimation);
            sb.Begin();
        }

        #endregion

        #region EVENTS

        // Timer iniziale
        private void startTimer_Tick(object sender, EventArgs e)
        {
            startTime = startTime.Subtract(TimeSpan.FromSeconds(1));
            if (startTime.Seconds < 2)
                TextBlockReady.Text = Locale.Strings.GO;
            if (startTime.Seconds < 1)
            {
                // The countdown is finished, the game can start
                startTimer.Tick -= startTimer_Tick;
                CanvasCountdown.Visibility = Visibility.Collapsed;
                timer.Start();
                UIgameTimer.Start();

                canvasBalloon.Visibility = Visibility.Visible;
                imageNut.Visibility = Visibility.Visible;

                ResetGame();
            }
        }

        // Click sul cilindro 
        void Box_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            HideItems();

            gameTime = 0;
            phase = GamePhaseAnimation.Rimuovi;

            HideBalloon();

            cilindroFront.MouseLeftButtonDown -= Box_MouseLeftButtonDown;
            canvasBalloon.MouseLeftButtonDown -= Box_MouseLeftButtonDown;
        }

        // Click su un opzione di risposta
        void solution_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            gameTime = 0;

            // Rimuove tutti gli eventi associati alle opzioni di risposta
            for (int i = 0; i < selectionNum; i++)
            {
                itemSolution[i].MouseLeftButtonDown -= solution_MouseLeftButtonDown;
            }

            // Risposta corretta
            if (((Item)sender).path == items[ItemRemoved].path)
            {
                ShowBalloon(Locale.Strings.LostWarningCorrect, "");

                giuste++;

                // Punti: 100 + (diff. lev * 10)
                if (difficulty > 2)
                    points += 100 + (difficulty * 20);
                else
                    points += 100 + (difficulty * 10);

                UIgameScore.SetScore(points);

                if (giuste % 2 == 0)
                {
                    difficulty++;
                    if (difficulty > 4) difficulty = 4;

                    // Incrementa numero possibili risposte
                    selectionNum++;
                    if (selectionNum > 6) selectionNum = 6;

                    // Incrementa numero di elementi visualizzati
                    elemNum++;
                    if (elemNum > 6) elemNum = 6;
                }

                // Mostra elemento mancante
                items[ItemRemoved].FadeIn();

                phase = GamePhaseAnimation.Risultato;
            }
            else
            {
                // Risposta sbagliata 

                //textBlockMessage.Text = "Sbagliato!!!";
                ShowBalloon(Locale.Strings.LostWarningWrong, "");

                sbagliate++;

                // Mostra elemento mancante
                items[ItemRemoved].FadeIn();

                phase = GamePhaseAnimation.Risultato;
            }
        }

        private void game_TimeOut(object sender, EventArgs e)
        {
            // Finito il tempo
            GameEventArgs gea = new GameEventArgs();
            gea.reason = GameCloseReason.Timeout;
            gea.score = this.points;
            gea.giuste = giuste;
            gea.sbagliate = sbagliate;

            if (GameEnd != null)
                GameEnd(this, gea);
        }

        private void Win_Close_Game(object sender, RoutedEventArgs e)
        {
            if (GameEnd != null)
            {
                GameEventArgs evtArgs = new GameEventArgs();
                evtArgs.reason = GameCloseReason.Victory;
                evtArgs.score = points;
                //evtArgs.gametime = 60 - Time;
                evtArgs.giuste = giuste;
                evtArgs.sbagliate = sbagliate;
                GameEnd(this, evtArgs);
            }
        }

        private void buttonClose_Click(object sender, RoutedEventArgs e)
        {
            if (GameEnd != null)
                GameEnd(this, null);
        }

        private void buttonReset_Click(object sender, RoutedEventArgs e)
        {
            ResetGame();
        }

        #endregion
    }
}
